/**
 * 
 */
package com.common.distributed.algorithm.RoundRobinWeight;

import java.util.ArrayList;
import java.util.List;

import com.common.distributed.algorithm.model.AlgorithmModel;
import com.common.distributed.algorithm.model.PartitionWeightParameter;
/**
 * @author liubing
 * 参考nginx 负载均衡算法
 */
public class RoundRobinWeightStrategy{
    private int i = -1; //表示上一次选择的服务器
    private int cw = 0; //表示当前调度的权值
    private int gcd = 0; //当前所有权重的最大公约数 比如 2，4，8 的最大公约数为：2
    private int maxWeight;

    private List<Integer> weights = null;  //作用计算最大公约数
    private PartitionWeightParameter weightRRParametersDns[] = null;

    public RoundRobinWeightStrategy(List<AlgorithmModel> algorithmModels) {

        this.initParam(algorithmModels);
    }

    private void initParam(List<AlgorithmModel> algorithmModels) {
        weightRRParametersDns = new PartitionWeightParameter[algorithmModels.size()];
        int numPart = 0;
        weights = new ArrayList<Integer>(algorithmModels.size());
        for(AlgorithmModel model:algorithmModels){
        	weights.add(model.getWeight());
        	weightRRParametersDns[numPart++] = new PartitionWeightParameter(model.getName(), model.getWeight());
        }
        gcd = getGcdByList(weights);
        maxWeight = getMaxWeight();
    }

    /**
     * 计算最大公约数
     * @param weight_m 权重数
     * @param weight_n 权重数
     * @return
     */
    private int GCD(int weight_m,int weight_n)
    {
        int temp;
        while(weight_n != 0){
            if(weight_m < weight_n){
                temp = weight_m;
                weight_m = weight_n;
                weight_n = temp;
            }
            temp = weight_m - weight_n;
            weight_m = weight_n;
            weight_n = temp;
        }
        return weight_m;
    }

    /**
     *
     * @param weights      权重列表
     * @param startIndex   list索引值,起始位置。
     * @param nextGcd      传入最大公约数
     * @return
     */
    private int getGcdByList(List<Integer> weights, int startIndex, int nextGcd) {
        if ( weights.size() < 2) {
            throw new IllegalArgumentException("At least a number of parameters for 2");
        }
        if (weights.size() == 2 && startIndex == 0) {
            return this.GCD(weights.get(startIndex), weights.get(startIndex + 1));
        }

        if (startIndex + 1 > weights.size() -1 )
            return nextGcd;
        int curGcd = nextGcd > 0 ? nextGcd : weights.get(startIndex);
        int nextIndex = startIndex + 1;
        nextGcd = GCD(curGcd, weights.get(startIndex + 1));              //0,1

        return getGcdByList(weights, nextIndex, nextGcd);
    }

    private int getGcdByList(List<Integer> weights) {
        return this.getGcdByList(weights, 0, 0);
    }

    private String getWeightDns() {
        for ( ; ; ) {
            i = (i + 1) % weightRRParametersDns.length;
            if (i == 0) {
                cw = cw - gcd;  //表示当前调度的权值
                if (cw <= 0) {
                    cw = maxWeight;
                    if (cw == 0) {
                        return null;
                    }
                }
            }

            if (weightRRParametersDns[i].getWeight() >= cw ) {
                return weightRRParametersDns[i].getPartition();
            }
        }
    }

    private int getMaxWeight() {
        int max = 0;
        for (int i = 0; i< weightRRParametersDns.length;i++) {
            if (weightRRParametersDns[i].getWeight() >= max) {
                max = weightRRParametersDns[i].getWeight();
            }
        }

        return max;
    }

    public String getPartitionIdForTopic() {
        return this.getWeightDns();
    }

    

}

